/*
 * Distance.java
 *
 * Copyright 2008 the Desert Labs Project (http://desertlabs.us)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package us.desertlabs.physics;

import java.math.BigDecimal;
import us.desertlabs.number.BigUtility;

/**
 * This is used to represent an amount of distance between two points.
 *
 * @author Brandon Franklin
 */
public class Distance extends SimpleUnit {

    private static final long serialVersionUID = 3258132453318014513L;

    /**
     * Given a pair of <CODE>Location</CODE>s, returns the <CODE>Distance</CODE>
     * between them.
     *
     * @param location1 the first <CODE>Location</CODE>
     * @param location2 the second <CODE>Location</CODE>
     * @return the <CODE>Distance</CODE> between the two <CODE>Location</CODE>s
     * @throws IllegalArgumentException if either of the parameters is invalid
     *         for any reason
     */
    static public Distance calculate( final Location location1, final Location location2 ) {

        // Validate the locations
        if( (location1 == null) || (location2 == null) ) {
            throw new IllegalArgumentException( "Location cannot be null." );

        } else if( (!location1.isValid()) || (!location2.isValid()) ) {
            throw new IllegalArgumentException( "Location is internally invalid." );

        } else if( location1.getDimensionality() != location2.getDimensionality() ) {
            throw new IllegalArgumentException( "Locations must have the same dimensionality." );

        } else if( location1.getSpace() != location2.getSpace() ) {
            throw new IllegalArgumentException( "Locations must exist in the same Space." );
        }

        // Sum of squares of differences
        BigDecimal total = BigDecimal.valueOf( 0 );
        final Number[] coords1 = location1.getCoordinates();
        final Number[] coords2 = location2.getCoordinates();
        for( int i = 0; i < coords1.length; i++ ) {
            BigDecimal p1 = new BigDecimal( coords1[i].toString() );
            final BigDecimal p2 = new BigDecimal( coords2[i].toString() );

            p1 = p1.subtract( p2 );
            p1 = p1.multiply( p1 );
            p1 = BigUtility.clipScale( p1 );

            total = total.add( p1 );
        }

        // Square root of sum
        final double sqrRoot = Math.sqrt( total.doubleValue() );

        return new Distance( BigUtility.clipScale( new BigDecimal( String.valueOf( sqrRoot ) ) ) );
    }

    /**
     * Creates a new instance of <CODE>Distance</CODE> representing the
     * supplied amount of distance.
     *
     * @param amount the amount of distance represented by this instance
     * @throws IllegalArgumentException if the supplied amount is null
     */
    public Distance( final Number amount ) {
        super( amount );
    }
}
